submodule(h5fortran:write) writer
!! This submodule is for writing 0-D..7-D data
use hdf5, only: h5dwrite_f

implicit none(type, external)

contains

module procedure h5write_scalar

integer(HID_T) :: filespace_id, dset_id
integer(HSIZE_T), allocatable :: dims(:)
integer :: ier

if (.not. self%is_open) error stop 'h5fortran:write: file handle is not open'

allocate (dims(0))

select type (value)
type is (real(real32))
    call hdf_create(self, dname, H5T_NATIVE_REAL, dims, filespace_id, dset_id, compact=compact)
    call h5dwrite_f(dset_id, H5T_NATIVE_REAL, value, dims, ier)
type is (real(real64))
    call hdf_create(self, dname, H5T_NATIVE_DOUBLE, dims, filespace_id, dset_id, compact=compact)
    call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE, value, dims, ier)
type is (integer(int32))
    call hdf_create(self, dname, H5T_NATIVE_INTEGER, dims, filespace_id, dset_id, compact=compact)
    call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER, value, dims, ier)
type is (integer(int64))
    call hdf_create(self, dname, H5T_STD_I64LE, dims, filespace_id, dset_id, compact=compact)
    call h5dwrite_f(dset_id, H5T_STD_I64LE, value, dims, ier)
type is (character(*))
    call h5ltmake_dataset_string_f(self%lid, dname, value, ier)
class default
    error stop "h5fortran:write: unknown type"
end select

if (ier /= 0) error stop 'h5fortran:write: could not write '//dname//' to '//self%filename

select type (value)
type is (character(*))
class default
    call hdf_wrapup(dset_id, filespace_id)
end select

end procedure h5write_scalar

module procedure h5write_1d
integer(HID_T) :: file_space_id, mem_space_id, dset_id, xfer_id, dtype
integer(HSIZE_T) :: dims(rank(value))
integer :: ier

xfer_id = H5P_DEFAULT_F

dims = shape(value, HSIZE_T)

select type (value)
type is (real(real32))
    dtype = H5T_NATIVE_REAL
type is (real(real64))
    dtype = H5T_NATIVE_DOUBLE
type is (integer(int32))
    dtype = H5T_NATIVE_INTEGER
type is (integer(int64))
    dtype = H5T_STD_I64LE
class default
    error stop "unknown variable type for "//dname
end select

call hdf_create(self, dname, dtype, dims, file_space_id, dset_id, chunk_size, istart, iend, stride, compact)

mem_space_id = H5S_ALL_F !< default

if (present(istart) .and. present(iend)) then
    call hdf_get_slice(self, dname, dset_id, file_space_id, mem_space_id, istart, iend, stride)
end if

select type (value)
type is (real(real32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (real(real64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
class default
    error stop "unknown variable type for "//dname
end select
if (ier /= 0) error stop 'h5fortran:ERROR: could not write '//dname//' to '//self%filename

call hdf_wrapup(dset_id, file_space_id)

end procedure h5write_1d

module procedure h5write_2d
integer(HID_T) :: file_space_id, mem_space_id, dset_id, xfer_id, dtype
integer(HSIZE_T) :: dims(rank(value))
integer :: ier

xfer_id = H5P_DEFAULT_F

dims = shape(value, HSIZE_T)

select type (value)
type is (real(real32))
    dtype = H5T_NATIVE_REAL
type is (real(real64))
    dtype = H5T_NATIVE_DOUBLE
type is (integer(int32))
    dtype = H5T_NATIVE_INTEGER
type is (integer(int64))
    dtype = H5T_STD_I64LE
class default
    error stop "unknown variable type for "//dname
end select

call hdf_create(self, dname, dtype, dims, file_space_id, dset_id, chunk_size, istart, iend, stride, compact)

mem_space_id = H5S_ALL_F !< default

if (present(istart) .and. present(iend)) then
    call hdf_get_slice(self, dname, dset_id, file_space_id, mem_space_id, istart, iend, stride)
end if

select type (value)
type is (real(real32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (real(real64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
class default
    error stop "unknown variable type for "//dname
end select
if (ier /= 0) error stop 'h5fortran:ERROR: could not write '//dname//' to '//self%filename

call hdf_wrapup(dset_id, file_space_id)

end procedure h5write_2d

module procedure h5write_3d
integer(HID_T) :: file_space_id, mem_space_id, dset_id, xfer_id, dtype
integer(HSIZE_T) :: dims(rank(value))
integer :: ier

xfer_id = H5P_DEFAULT_F

dims = shape(value, HSIZE_T)

select type (value)
type is (real(real32))
    dtype = H5T_NATIVE_REAL
type is (real(real64))
    dtype = H5T_NATIVE_DOUBLE
type is (integer(int32))
    dtype = H5T_NATIVE_INTEGER
type is (integer(int64))
    dtype = H5T_STD_I64LE
class default
    error stop "unknown variable type for "//dname
end select

call hdf_create(self, dname, dtype, dims, file_space_id, dset_id, chunk_size, istart, iend, stride, compact)

mem_space_id = H5S_ALL_F !< default

if (present(istart) .and. present(iend)) then
    call hdf_get_slice(self, dname, dset_id, file_space_id, mem_space_id, istart, iend, stride)
end if

select type (value)
type is (real(real32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (real(real64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
class default
    error stop "unknown variable type for "//dname
end select
if (ier /= 0) error stop 'h5fortran:ERROR: could not write '//dname//' to '//self%filename

call hdf_wrapup(dset_id, file_space_id)

end procedure h5write_3d

module procedure h5write_4d
integer(HID_T) :: file_space_id, mem_space_id, dset_id, xfer_id, dtype
integer(HSIZE_T) :: dims(rank(value))
integer :: ier

xfer_id = H5P_DEFAULT_F

dims = shape(value, HSIZE_T)

select type (value)
type is (real(real32))
    dtype = H5T_NATIVE_REAL
type is (real(real64))
    dtype = H5T_NATIVE_DOUBLE
type is (integer(int32))
    dtype = H5T_NATIVE_INTEGER
type is (integer(int64))
    dtype = H5T_STD_I64LE
class default
    error stop "unknown variable type for "//dname
end select

call hdf_create(self, dname, dtype, dims, file_space_id, dset_id, chunk_size, istart, iend, stride, compact)

mem_space_id = H5S_ALL_F !< default

if (present(istart) .and. present(iend)) then
    call hdf_get_slice(self, dname, dset_id, file_space_id, mem_space_id, istart, iend, stride)
end if

select type (value)
type is (real(real32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (real(real64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
class default
    error stop "unknown variable type for "//dname
end select
if (ier /= 0) error stop 'h5fortran:ERROR: could not write '//dname//' to '//self%filename

call hdf_wrapup(dset_id, file_space_id)

end procedure h5write_4d

module procedure h5write_5d
integer(HID_T) :: file_space_id, mem_space_id, dset_id, xfer_id, dtype
integer(HSIZE_T) :: dims(rank(value))
integer :: ier

xfer_id = H5P_DEFAULT_F

dims = shape(value, HSIZE_T)

select type (value)
type is (real(real32))
    dtype = H5T_NATIVE_REAL
type is (real(real64))
    dtype = H5T_NATIVE_DOUBLE
type is (integer(int32))
    dtype = H5T_NATIVE_INTEGER
type is (integer(int64))
    dtype = H5T_STD_I64LE
class default
    error stop "unknown variable type for "//dname
end select

call hdf_create(self, dname, dtype, dims, file_space_id, dset_id, chunk_size, istart, iend, stride, compact)

mem_space_id = H5S_ALL_F !< default

if (present(istart) .and. present(iend)) then
    call hdf_get_slice(self, dname, dset_id, file_space_id, mem_space_id, istart, iend, stride)
end if

select type (value)
type is (real(real32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (real(real64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
class default
    error stop "unknown variable type for "//dname
end select
if (ier /= 0) error stop 'h5fortran:ERROR: could not write '//dname//' to '//self%filename

call hdf_wrapup(dset_id, file_space_id)

end procedure h5write_5d

module procedure h5write_6d
integer(HID_T) :: file_space_id, mem_space_id, dset_id, xfer_id, dtype
integer(HSIZE_T) :: dims(rank(value))
integer :: ier

xfer_id = H5P_DEFAULT_F

dims = shape(value, HSIZE_T)

select type (value)
type is (real(real32))
    dtype = H5T_NATIVE_REAL
type is (real(real64))
    dtype = H5T_NATIVE_DOUBLE
type is (integer(int32))
    dtype = H5T_NATIVE_INTEGER
type is (integer(int64))
    dtype = H5T_STD_I64LE
class default
    error stop "unknown variable type for "//dname
end select

call hdf_create(self, dname, dtype, dims, file_space_id, dset_id, chunk_size, istart, iend, stride, compact)

mem_space_id = H5S_ALL_F !< default

if (present(istart) .and. present(iend)) then
    call hdf_get_slice(self, dname, dset_id, file_space_id, mem_space_id, istart, iend, stride)
end if

select type (value)
type is (real(real32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (real(real64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
class default
    error stop "unknown variable type for "//dname
end select
if (ier /= 0) error stop 'h5fortran:ERROR: could not write '//dname//' to '//self%filename

call hdf_wrapup(dset_id, file_space_id)

end procedure h5write_6d

module procedure h5write_7d
integer(HID_T) :: file_space_id, mem_space_id, dset_id, xfer_id, dtype
integer(HSIZE_T) :: dims(rank(value))
integer :: ier

xfer_id = H5P_DEFAULT_F

dims = shape(value, HSIZE_T)

select type (value)
type is (real(real32))
    dtype = H5T_NATIVE_REAL
type is (real(real64))
    dtype = H5T_NATIVE_DOUBLE
type is (integer(int32))
    dtype = H5T_NATIVE_INTEGER
type is (integer(int64))
    dtype = H5T_STD_I64LE
class default
    error stop "unknown variable type for "//dname
end select

call hdf_create(self, dname, dtype, dims, file_space_id, dset_id, chunk_size, istart, iend, stride, compact)

mem_space_id = H5S_ALL_F !< default

if (present(istart) .and. present(iend)) then
    call hdf_get_slice(self, dname, dset_id, file_space_id, mem_space_id, istart, iend, stride)
end if

select type (value)
type is (real(real32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (real(real64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int32))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
type is (integer(int64))
    call h5dwrite_f(dset_id, dtype, value, dims, ier, file_space_id=file_space_id, mem_space_id=mem_space_id, xfer_prp=xfer_id)
class default
    error stop "unknown variable type for "//dname
end select
if (ier /= 0) error stop 'h5fortran:ERROR: could not write '//dname//' to '//self%filename

call hdf_wrapup(dset_id, file_space_id)

end procedure h5write_7d

end submodule writer
